package com.example.aigc_education.controller;


import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.example.aigc_education.anno.RequestKeyParam;
import com.example.aigc_education.anno.RequestLock;
import com.example.aigc_education.constant.HttpStatus;
import com.example.aigc_education.domain.Exam;
import com.example.aigc_education.domain.Question;
import com.example.aigc_education.domain.User;
import com.example.aigc_education.domain.dto.*;
import com.example.aigc_education.domain.po.*;
import com.example.aigc_education.domain.vo.BindSuccessVO;
import com.example.aigc_education.domain.vo.IdVO;
import com.example.aigc_education.mapper.AnswerMapper;
import com.example.aigc_education.mapper.QuestionMapper;
import com.example.aigc_education.security.domain.LoginUser;
import com.example.aigc_education.security.service.TokenService;
import com.example.aigc_education.service.impl.AnswerServiceImpl;
import com.example.aigc_education.service.impl.ExamServiceImpl;
import com.example.aigc_education.service.impl.UserCourseServiceImpl;
import com.example.aigc_education.service.impl.UserServiceImpl;
import com.example.aigc_education.utils.ResultUtil;
import com.example.aigc_education.utils.SecurityUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.protocol.HTTP;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.BitFieldSubCommands;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.time.LocalDate;
import java.time.YearMonth;
import java.util.*;

/**
 * 用户控制器类，负责处理用户相关的HTTP请求。
 */

@Slf4j
@RestController
@RequestMapping("/user")
public class UserController {
    @Resource
    private UserServiceImpl userService; // 注入用户服务实现类
    @Resource
    private TokenService tokenService;
    @Resource
    private UserCourseServiceImpl userCourseService;

    @Resource
    private ExamServiceImpl examService;

    @Resource
    private QuestionMapper questionMapper;

    @Resource
    private AnswerServiceImpl answerService;

    /**
     * 通过用户名登录
     *
     * @param loginByUsernameDto 包含登录所需信息的DTO（数据传输对象），包括用户名、密码、验证码和UUID
     * @return 返回登录结果，其中包含token
     */

    @PostMapping("/loginByUsername")
    public ResultUtil loginByUsername(@RequestBody LoginByUsernameDTO loginByUsernameDto) {
        ResultUtil result = ResultUtil.success(); // 初始化登录成功结果
        String token = userService.loginByUsername(loginByUsernameDto.getUsername(), loginByUsernameDto.getPassword(), loginByUsernameDto.getCode(), loginByUsernameDto.getUuid()); // 执行用户名登录
        result.put("token", token); // 将生成的token添加到结果中
        return result;
    }

    /**
     * 重置密码
     *
     * @param password（数据传输对象），新密码
     * @return 返回修改成功否
     */

    @PostMapping("/resetPassword")
    public ResultUtil resetPassword(String password) {
        userService.resetPassword(password);
        return ResultUtil.success("密码重置成功");
    }


    /**
     * 通过手机号登录
     *
     * @param loginByMobileDto 包含登录所需信息的DTO，包括手机号和验证码
     * @return 返回登录结果，其中包含token
     */
    @PostMapping("/loginByMobile")
    public ResultUtil loginByMobile(@RequestBody LoginByMobileDTO loginByMobileDto) {
        ResultUtil result = ResultUtil.success(); // 初始化登录成功结果
        String token = userService.loginByPhone(loginByMobileDto.getPhone(), loginByMobileDto.getCode()); // 执行手机登录
        result.put("token", token); // 将生成的token添加到结果中
        return result;
    }

    /**
     * 获取用户信息(不返回密码)
     * <p>
     * 本方法不需要接受任何参数，通过当前登录用户的用户名，从数据库中查询该用户的信息，并将其封装在ResultUtil对象中返回。
     *
     * @return ResultUtil 包含用户信息的成功结果对象，如果查询失败则返回相应的错误信息。
     */
    @GetMapping("/getInfo")
    public ResultUtil getInfo() {
        // 获取当前登录的用户对象
        LoginUser loginUser = SecurityUtils.getLoginUser();
        User user = loginUser.getUser();

        // 查询并封装用户信息，返回成功结果
        ResultUtil result = ResultUtil.success(userService.getUserByUsername(user.getUserName()));
        return result;
    }

    /**
     * 更新用户信息
     *
     * @param modifyByUserDto 包含用户修改信息的数据传输对象，通过RequestBody接收前端传来的JSON数据。
     * @return ResultUtil 返回一个结果工具对象，其中包含操作是否成功的信息及消息文本。
     */
    @PostMapping("/updateInfo")
    public ResultUtil updateInfo(@RequestBody ModifyByUserDTO modifyByUserDto) {
//        String json = JSON.toJSONString(modifyByUserDto);
//        log.info("updateInfo: " + json);
        // 根据用户ID和修改信息尝试更新用户信息
        Boolean is_update = userService.updateInfoByUserId(SecurityUtils.getUserId(), modifyByUserDto);
        // 若更新成功，返回成功结果信息
        return ResultUtil.success("用户信息更新成功");

    }


//    @PostMapping("modifyPassword")
//    public ResultUtil modifyPassword(@RequestBody ModifyPwdByUserDTO modifyPwdByUserDTO, HttpServletRequest request){
//        String token = userService.modifyPassword(SecurityUtils.getUserId(), modifyPwdByUserDTO);
//        ResultUtil result = ResultUtil.success();
//        result.put("token", token);
//        result.put("message", "密码修改成功");
//        log.info(SecurityUtils.getLoginUser().getToken());
//        return result;
//    }


    /**
     * 通过GET请求获取当前登录教师执教的课程列表
     * <p>
     * 该接口使用了Spring MVC的@GetMapping注解，指定请求方法为GET，并定义了请求的URL路径为/teacher/getTeacherCourse。
     * 同时，使用了@PreAuthorize注解来指定访问该接口需要具备的权限，这里是'sys:teacher:course'权限。
     * 接口的主要功能是查询并返回当前登录教师的课程列表。首先，通过SecurityUtils.getUserId()方法获取当前登录用户的ID，
     * 然后调用userService的selectCourseNameByUserId方法，传入用户ID，查询该用户对应的课程名称列表。
     * 最后，使用ResultUtil的success方法返回查询结果，其中courseList作为成功结果的数据部分返回。
     *
     * @return ResultUtil 对象，包含操作结果状态码和课程列表数据。
     */
/*    @GetMapping("/teacher/getCourse")
    @PreAuthorize("hasAuthority('sys:teacher:course')")
    public ResultUtil getTeaCourse(){
        // 根据当前登录用户的ID查询其对应的课程名称列表
        List<String> courseList = userCourseService.selectCourseNameByUserId(SecurityUtils.getUserId());
        // 返回查询结果，标记为成功操作
        return ResultUtil.success(courseList);
    }*/


    /**
     * 教师通过课程ID或者班级ID获取选课学生列表
     * 此方法允许任课教师查看特定课程的选课学生列表。
     * 允许班主任查看特定班级的学生列表。(不传courseId)
     * 教师需要具有'sys:course:student'权限才能访问此接口。
     *
     * @param courseId 课程ID，用于查询选课学生列表。
     * @return 返回包含选课学生信息的结果对象。如果操作成功，结果对象中的data字段将包含学生列表。
     */
/*    @PostMapping("/teacher/getCourseStu")
    @PreAuthorize("hasAuthority('sys:course:student')")
    public ResultUtil getCourseStu(Long courseId){
        // 根据课程ID和当前登录教师的用户ID查询选课学生列表
        List<SelectStuByTeacherPO> userList = userCourseService.selectStuList(courseId, SecurityUtils.getUserId());
        // 返回查询结果，操作成功
        return ResultUtil.success(userList);
    }*/


    /**
     * 获取学生选修课程信息
     * <p>
     * 本接口用于查询当前登录学生所选的课程信息。通过预授权注解确保只有具备相应权限的用户可以访问。
     * 使用@GetMapping注解定义了请求的方法和路径，@PreAuthorize注解用于权限检查。
     *
     * @return ResultUtil 返回一个包含操作结果和选修课程信息的响应对象。
     * 如果操作成功，选修课程信息作为数据部分包含在响应中。
     */
    @GetMapping("/student/getCourse")
    @PreAuthorize("hasAuthority('sys:student:course')")
    public ResultUtil getStuCourse() {
        // 通过SecurityUtils.getUserId()获取当前登录用户的ID，用于查询用户的选修课程
        // 根据当前登录学生的ID查询其对应的课程名称列表
        List<SelectCourseByStuPO> selectCourseByStuPOS = userCourseService.selectStuCourse(SecurityUtils.getUserId());
        // 返回操作成功的结果，并将查询到的选修课程信息作为数据部分包含在响应中
        return ResultUtil.success(selectCourseByStuPOS);
    }

    /**
     * 通过GET请求获取考试信息
     * <p>
     * 此方法注解了@GetMapping，指明了请求的URL路径为/student/getExam，用于特定的HTTP GET请求。
     * 同时使用了@PreAuthorize注解，确保只有拥有'sys:student:exam'权限的用户才能访问此方法。
     *
     * @return ResultUtil 对象，包含操作结果和考试信息列表。如果操作成功，考试信息列表将包含当前用户可以查看的考试名称。
     */
    @GetMapping("/getExam")
    @PreAuthorize("hasAuthority('sys:user:exam')")
    public ResultUtil getStuExam() {
        // 调用examService的selectExamNameByUserId方法，根据当前登录用户的ID获取相应的考试名称列表。
        List<Exam> exams = examService.selectExamByUserId(SecurityUtils.getUserId());
        // 返回操作结果为成功的ResultUtil对象，并包含获取到的考试信息列表。
        return ResultUtil.success(exams);
    }

    /**
     * 根据考试状态获取学生考试信息
     * <p>
     * 该接口通过学生的状态码查询其对应的考试信息。仅授权拥有特定权限的用户可以访问。
     * 使用了Spring Security的权限注解@PreAuthorize来限制访问。
     *
     * @param status 考试的状态码，用于过滤考试信息。
     * @return 返回包含查询结果的ResultUtil对象。如果查询成功，ResultUtil的success方法将返回考试信息列表。
     */
    @PostMapping("/student/getExamByStatus")
    @PreAuthorize("hasAuthority('sys:student:exam')")
    public ResultUtil getStuExamByStatus(Integer status) {
        // 根据当前登录用户的ID和指定的考试状态，查询考试信息。
        List<Exam> exams = examService.selectExamByUserIdAndStatus(SecurityUtils.getUserId(), status);
        // 返回查询结果，如果成功，则包含考试信息列表。
        return ResultUtil.success(exams);
    }


    /**
     * 根据用户id和考试类型获取用户考试成绩
     * <p>
     * 该方法通过POST请求访问，路径为"getGradesByType"。它需要用户具有"sys:student:grades"的权限才能访问。
     * 方法的主要功能是根据考试类型和当前登录用户的ID，从数据库中查询该用户的考试成绩列表。
     *
     * @param examType 考试类型，用于筛选考试成绩。不同的考试类型代表不同的考试类别，如期中考试、期末考试等。
     * @return 返回一个包含查询到的考试成绩列表的结果对象。如果查询成功，考试成绩列表将包含在结果对象的成功数据部分。
     */
    @PostMapping("/student/getGradesByType")
    @PreAuthorize("hasAuthority('sys:student:exam')")
    public ResultUtil getGradesByType(Integer examType) {
        if (examType == null) {
            // 根据当前用户ID查询其所有考试成绩
            List<Exam> exams = examService.selectGrades(SecurityUtils.getUserId());
            // 返回查询结果作为成功响应
            return ResultUtil.success(exams);
        }
        // 调用examService的selectGradesByExamType方法，查询当前用户ID和指定考试类型下的考试成绩列表。
        // 根据当前用户ID和考试类型查询其考试成绩
        List<Exam> exams = examService.selectGradesByExamType(SecurityUtils.getUserId(), examType);
        // 构造并返回一个成功结果对象，其中包含查询到的考试成绩列表。
        // 返回查询结果作为成功响应
        return ResultUtil.success(exams);
    }


    /**
     * 父母通过孩子用户ID和考试类型获取考试成绩列表
     * 此方法专门处理父母用户查询其子女的考试成绩的请求。
     * 使用者必须具有'sys:parents:grades'权限才能访问此方法。
     *
     * @param userId 父母用户ID，用于查询与此ID关联的子女的考试成绩。
     * @return ResultUtil 对象，包含查询结果的成功响应。如果查询成功，exams 列表将包含所有子女的考试成绩。
     */
    @PostMapping("/parents/getGrades")
    @PreAuthorize("hasAuthority('sys:parents:grades')")
    public ResultUtil getGrades(Long userId, Integer examType) {
        if (examType == null) {
            // 通过考试服务查询指定用户ID的子女的考试成绩列表。
            List<Exam> exams = examService.selectGrades(userId);
            // 返回包含查询到的考试成绩列表的成功响应。
            return ResultUtil.success(exams);
        } else {
            // 调用examService的selectGradesByExamType方法，查询指定用户ID和考试类型的考试成绩列表。
            List<Exam> exams = examService.selectGradesByExamType(userId, examType);
            return ResultUtil.success(exams);
        }
    }

    /**
     * 任课教师通过学生ID和课程ID获取课程成绩信息
     * 此方法仅对具有'sys:teacher:grades'权限的用户开放。
     *
     * @param userId 教师的用户ID，用于确定请求的教师身份。
     * @param courseId 课程的ID，用于筛选特定课程的成绩信息。
     * @return 返回包含选中课程考试信息的结果对象，如果成功，则状态码为200。
     */
/*    @PostMapping("/teacher/getCourseGrades")
    @PreAuthorize("hasAuthority('sys:teacher:grades')")
    public ResultUtil getGrades(Long userId, Long courseId){
        // 根据课程ID和教师ID查询相关的考试信息。
        List<SelectExamByCourseIdPO> selectExamByCourseIdPOS = examService.selectExamByCourseIdAndUserId(courseId, userId);
        // 返回查询结果作为成功响应。
        return ResultUtil.success(selectExamByCourseIdPOS);
    }*/

    /**
     * 班主任根据班级ID获取班级成绩信息
     * <p>
     * 该方法通过GET请求访问，用于教师查询特定班级的所有课程考试成绩。
     * 使用了Spring Security的@PreAuthorize注解来限制访问权限，只有具备'sys:teacher:grades'权限的用户才能访问。
     *
     * @param classId 班级的唯一标识ID，用于查询该班级的考试成绩信息。
     * @return 返回一个ResultUtil对象，其中包含查询到的考试成绩信息。如果查询成功，ResultUtil的status为200，data字段为考试成绩列表；如果查询失败，根据具体情况设置status和msg字段。
     */
    @GetMapping("/teacher/getClassGrades")
    @PreAuthorize("hasAuthority('sys:teacher:grades')")
    public ResultUtil getClassGrades(Long classId) {
        // 根据班级ID查询考试成绩信息
        List<SelectExamByCourseIdPO> selectExamByCourseIdPOS = examService.selectExamByClassId(classId);
        // 返回查询结果，如果查询成功，将考试成绩列表作为数据部分返回
        return ResultUtil.success(selectExamByCourseIdPOS);
    }


    /**
     * 更新考试成绩
     * 该接口仅允许具有"sys:teacher:grades"权限的用户访问。
     * 通过考试ID、分数来更新考试成绩。
     *
     * @param examId 考试的唯一标识符，用于定位要更新成绩的考试。
     * @param score  学生在考试中得到的分数，用于更新考试成绩。
     * @return 返回一个结果对象，其中包含操作的成功信息。
     */
    @GetMapping("/teacher/updateGrades")
    @PreAuthorize("hasAuthority('sys:teacher:grades')")
    public ResultUtil updateGrades(Long examId, Integer score) {
        // 调用考试服务更新指定考试的分数
        examService.updateScore(examId, score);
        // 返回操作成功的结果信息
        return ResultUtil.success("成绩更新成功");
    }

    /**
     * 填充学习风格 (合并到updateInfo接口)
     *
     * @param studyStyle 学习风格
     * @return 返回填充成功
     */
    @PostMapping("/addStudyStyle")
    public ResultUtil addStuStudyStyle(String studyStyle) {
        Long userId = SecurityUtils.getUserId();
        User user = userService.getOne(new LambdaQueryWrapper<User>().eq(User::getUserId, userId));
        user.setStudyStyle(studyStyle);
        userService.updateById(user);
        return ResultUtil.success("学习风格填充成功");
    }

    /**
     * 通过答题内容获取AI测评学生学习风格
     *
     * @param studyStyleQuestion 学习风格问题集
     * @return 返回ai评价学习风格
     */
    @GetMapping("/aiStudyStyle")
    public ResultUtil getAiStudyStyle(String studyStyleQuestion) {
        String res = userService.getAiStudyStyle(studyStyleQuestion);
        HashMap<String, Object> data = new HashMap<>();
        data.put("AIAnswer", res);
        return ResultUtil.success("ai测评学习风格", data);
    }


    /**
     * 检查用户学习风格是否填充
     *
     * @return 返回学习风格填充状态
     */
    @GetMapping("/checkStudyStyle")
    public ResultUtil checkStudyStyle() {
        Long userId = SecurityUtils.getUserId();
        User user = userService.getOne(new LambdaQueryWrapper<User>().eq(User::getUserId, userId));
        if (user.getStudyStyle() == null) {
            return ResultUtil.error(HttpStatus.NO_CONTENT, "学习风格未填充");
        }
        return ResultUtil.success("学习风格已填充");
    }

    /**
     * 检查用户学习习惯是否填充
     *
     * @return 返回学习习惯填充状态
     */
    @GetMapping("/checkStudyHabit")
    public ResultUtil checkStudyHabit() {
        return null;
    }

    /**
     * 设置用户学习习惯
     *
     * @param jsonContent 学习习惯内容
     * @return 返回设置学习习惯结果
     */
    @PostMapping("/setStudyHabit")
    public ResultUtil setStudyHabit(String jsonContent) {
        return null;
    }


    /**
     * 根据考试ID获取试卷中的题目列表
     * 该接口通过接收考试ID（examId），从数据库中查询对应考试的题目列表，并返回给前端。
     * 主要用于在线考试系统中，教师或系统管理员获取指定试卷的题目集合，以供展示或进一步处理。
     *
     * @param examId 考试ID，用于唯一标识一个考试。
     * @return 返回包含题目列表的结果对象，如果查询成功，题目列表将包含在结果的"data"字段中。
     */
    @PostMapping("/getPaperQuestion")
    public ResultUtil getPaperQuestion(Long examId) {
        // 根据考试ID查询该考试的所有题目
        List<Question> questions = questionMapper.selectExamQuestionByExamId(examId);
        // 返回查询结果，如果查询成功，则将题目列表封装在成功结果中返回
        return ResultUtil.success(questions);
    }


    /**
     * 教师通过考试ID和题目ID获取本场考试单个题目的学生作答情况
     * 此方法用于处理来自前端的POST请求，请求路径为/getSingleAnswer。
     * 主要功能是查询指定考试和题目下的用户答案信息。
     *
     * @param examId     考试的唯一标识符，用于定位答案所属的考试。
     * @param questionId 题目的唯一标识符，用于定位答案所属的题目。
     * @return 返回一个ResultUtil对象，其中包含查询到的用户答案信息。
     * 如果查询成功，ResultUtil的status字段为200，data字段为查询结果。
     * 如果查询失败，ResultUtil的status字段为其他值，data字段为空或包含错误信息。
     */
    @PostMapping("teacher/getSingleAnswer")
    @PreAuthorize("hasAuthority('sys:teacher:singleAnswer')")
    public ResultUtil getSingleAnswer(Long examId, Long questionId) {
        // 调用answerService的selectSingleAnswerStation方法查询用户答案
        List<SelectAnswerByQuestionPO> selectAnswerByQuestionPOS = answerService.selectSingleAnswerStation(questionId, examId);
        // 构造并返回成功结果，其中包含查询到的用户答案信息
        return ResultUtil.success(selectAnswerByQuestionPOS);
    }


    /**
     * 学生通过考试ID和用户ID获取考试答题详情
     * 此方法用于处理针对特定考试和用户，获取用户答题详情的请求。
     * 它从数据库中检索用户在给定考试中的答案及其相关问题，并将这些信息封装在ResultUtil对象中返回。
     *
     * @param examId 考试的唯一标识符，用于定位特定的考试。
     * @param userId 用户的唯一标识符，用于确定答案所属的用户。
     * @return ResultUtil 对象，其中包含用户在指定考试中的答案详情。
     */
    @PostMapping("/getAnswerDetail")
    public ResultUtil getAnswerDetail(Long examId, Long userId) {
        // 调用answerService中的方法，根据用户ID和考试ID查询用户的答题情况。
        List<SelectAnswerByUserPO> selectAnswerByUserPOS = answerService.selectAnswerAndQuestionByUser(userId, examId);
        // 将查询结果封装在ResultUtil对象中，并设置为成功状态，然后返回。
        return ResultUtil.success(selectAnswerByUserPOS);
    }


    /**
     * 签到
     *
     * @param signReward 今日签到奖励
     * @return ResultUtil 对象
     */
    @RequestLock(prefix = "sign:", expire = 3)
    @PostMapping("/sign")
    public ResultUtil sign(@RequestKeyParam Integer signReward) {
        return userService.sign(signReward);
    }


    /**
     * 签到页面展示
     *
     * @return ResultUtil 对象，其中包含用户所看到的奖励值以及他的连续签到日
     */
    @GetMapping("/sign/view")
    public ResultUtil getSignRewardView() {
        return userService.getSignRewardView();
    }

    /**
     * 签到月页面展示
     *
     * @return ResultUtil 对象，其中包含用户该月份的所有签到记录
     */
    @GetMapping("/sign/monthView")
    public ResultUtil getSignMothView() {
        return userService.getSignMothView();
    }


//    /**
//     * 忘记密码接口
//     * 通过手机、验证码和新密码来重置用户密码。
//     *
//     * @param phone 用户的电话号码，用于识别用户。
//     * @param code 用户收到的验证码，用于验证用户身份。
//     * @param password 用户设置的新密码，用于重置旧密码。
//     * @return 返回一个结果对象，包含操作是否成功的提示信息。
//     */
//    @GetMapping("/forgetPassword")
//    public ResultUtil forgetPassword(String phone, String code, String password) {
//        // 调用用户服务层的方法，通过手机、验证码和新密码来修改用户的密码。
//        userService.modifyPasswordByPhone(phone, password, code);
//        // 返回一个成功结果，包含密码修改成功的提示信息。
//        return ResultUtil.success("密码修改成功");
//    }


}

